package extend

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"golang.org/x/crypto/bcrypt"
	"io"
	"os"
	"sort"
)

// Md5 md5加密
func Md5(value string) string {
	m := md5.New()
	m.Write([]byte(value))
	return hex.EncodeToString(m.Sum(nil))
}

// Sha1 sha1加密
func Sha1(value string) string {
	m := sha1.New()
	m.Write([]byte(value))
	return hex.EncodeToString(m.Sum(nil))
}

// RsaEncrypt rsa加密
func RsaEncrypt(origData []byte, publicKey []byte) ([]byte, error) {
	//解密pem格式的公钥
	block, _ := pem.Decode(publicKey)
	if block == nil {
		return nil, errors.New("public key error")
	}
	// 解析公钥
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	// 类型断言
	pub := pubInterface.(*rsa.PublicKey)
	//加密
	return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}

// RsaDecrypt rsa解密
func RsaDecrypt(ciphertext []byte, privateKey []byte) ([]byte, error) {
	//解密
	block, _ := pem.Decode(privateKey)
	if block == nil {
		return nil, errors.New("private key error")
	}
	//解析PKCS1格式的私钥
	pri, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	// 解密
	return rsa.DecryptPKCS1v15(rand.Reader, pri, ciphertext)
}

// FileGetContents 读取文件内容
func FileGetContents(fileName string) (content []byte, err error) {
	file, err := os.Open(fileName)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	// 读取文件全部内容
	content, err = io.ReadAll(file)
	if err != nil {
		return nil, err
	}
	return content, nil
}

// FilePutContents 写入文件
func FilePutContents(fileName string, content []byte, flag int) error {
	if flag == 0 {
		flag = os.O_CREATE | os.O_WRONLY | os.O_TRUNC
	} else {
		flag = os.O_CREATE | os.O_WRONLY | flag
	}
	file, err := os.OpenFile(fileName, flag, 0644)
	if err != nil {
		return err
	}
	defer file.Close()
	_, err = file.Write(content)
	if err != nil {
		return err
	}
	return nil
}

// FileExists 检查文件是否存在
func FileExists(fileName string) (bool, error) {
	//指定要检查的文件路径 使用 os.Stat 检查文件
	_, err := os.Stat(fileName)
	if os.IsNotExist(err) {
		return false, err
	} else if err != nil {
		// 处理其他类型的错误
		return false, err
	} else {
		return true, nil
	}
}

// KSort 对map进行排序
func KSort(m map[string]string) []struct {
	Key   string
	Value string
} {
	// 提取 map 的键到一个切片中
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	// 对键切片进行排序
	sort.Strings(keys)
	// 创建一个结构体切片，用于存储排序后的键值对
	sortedPairs := make([]struct {
		Key   string
		Value string
	}, len(keys))
	// 遍历排序后的键，填充结构体切片
	for i, k := range keys {
		sortedPairs[i] = struct {
			Key   string
			Value string
		}{k, m[k]}
	}
	return sortedPairs
}

// InArray 判断字符串是否在Array中
func InArray(slice []string, val string) bool {
	set := make(map[string]struct{})
	for _, item := range slice {
		set[item] = struct{}{}
	}
	_, found := set[val]
	return found
}

// PasswordHash 密码加密
func PasswordHash(password string) (string, error) {
	// bcrypt.GenerateFromPassword 用于生成密码哈希
	hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}
	// 返回哈希后的密码字符串
	return string(hashedBytes), nil
}

// PasswordVerify 密码验证
func PasswordVerify(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}
